using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

namespace dotIRC
{
    public class IrcRtf : RichTextBox
    {
        const string BARE_HEADER = "{\\rtf1{\\colortbl;\\red255\\green255\\blue255;\\red0\\green0\\blue0;\\red0\\green0\\blue128;\\red0\\green128\\blue0;\\red255\\green0\\blue0;\\red128\\green0\\blue0;\\red128\\green0\\blue128;\\red255\\green128\\blue0;\\red255\\green255\\blue0;\\red0\\green255\\blue0;\\red0\\green128\\blue128;\\red0\\green255\\blue255;\\red0\\green0\\blue255;\\red255\\green0\\blue255;\\red128\\green128\\blue128;\\red192\\green192\\blue192;}";
        const string BARE_FOOTER = "\\par}";

        public static string TimeStamp()
        {
            return TimeStamp(DateTime.Now);
        }
        public static string TimeStamp(DateTime dateTime)
        {
            return "\\b[" + dateTime.ToString() + "]\\b0  ";
        }
        public static string NickTag(string nick)
        {
            return "<\\b " + nick + "\\b0> ";
        }

        public static string Format(string message)
        {
            StringBuilder outputMsg = new StringBuilder();
            bool isBold = false;
            bool isULine = false;
            for (int i=0;i<message.Length;i++)
            {
                switch (message[i])
                {
                    case '\x02':
                        if (!isBold)
                            outputMsg.Append("\\b ");
                        else
                            outputMsg.Append("\\b0 ");
                        isBold = !isBold;
                        break;

                    case '\x03':
                        string fcolorstr = string.Empty;
                        string bcolorstr = string.Empty;
                        int tagindex = i;
                        for (i++; message[i] >= '0' && message[i] <= '9' && i <= (tagindex + 2); i++)
                            fcolorstr += message[i];
                        if (message[i] == ',')
                        {
                            tagindex = i;
                            for (i++; message[i] >= '0' && message[i] <= '9' && i <= (tagindex + 2); i++)
                                bcolorstr += message[i];
                        }
                        if (bcolorstr == "99") bcolorstr = string.Empty;
                        if (fcolorstr == "99")
                        {
                            if (bcolorstr == "99") fcolorstr = bcolorstr;
                            else fcolorstr = string.Empty;
                        }

                        if (fcolorstr != string.Empty)
                            outputMsg.Append("\\cf" + colorNum(fcolorstr) + " ");
                        if (bcolorstr != string.Empty)
                            outputMsg.Append("\\highlight" + colorNum(bcolorstr) + " ");
                        if (fcolorstr == string.Empty && bcolorstr == string.Empty)
                            outputMsg.Append("\\cf0\\highlight0 ");
                        outputMsg.Append(message[i]); // Keep the good character pointed by the i++ that ended the parse loop.

                        break;

                    case '\x0f':
                        outputMsg.Append("\\b0\\ul0\\cf0\\highlight0 ");
                        isBold = isULine = false;
                        break;

                    case '\x16': // decimal 22
                        //Reverse not implemented yet!
                        break;

                    case '\x1f': // decimal 33
                        if (!isULine)
                            outputMsg.Append("\\ul ");
                        else
                            outputMsg.Append("\\ul0 ");
                        isULine = !isULine;
                        break;

                    case '\\':
                        outputMsg.Append("\\\\");
                        break;

                    case '{':
                        outputMsg.Append("\\{");
                        break;

                    case '}':
                        outputMsg.Append("\\}");
                        break;

                    default:
                        outputMsg.Append(message[i]);
                        break;
                }
            }
            return outputMsg.ToString();
        }

        static int colorNum(string colorstr)
        {
            int color = int.Parse(colorstr);
            while (color > 15 && color != 99) color %= 16; // If color code is unknown, fix it.
            color++;
            return color;
        }
        
        public static string Plain(string message)
        {
            bool isColorCode = false;
            StringBuilder outputMsg = new StringBuilder();
            for (int i = 0; i < message.Length; i++)
            {
                if (isColorCode)
                {
                    int tagindex = i;
                    if (message[i] >= '0' && message[i] <= '9' && i <= (tagindex + 2))
                        continue;
                    else if (message[i] == ',') tagindex = i;
                    else isColorCode = false;
                }

                switch (message[i])
                {
                    case '\x02':
                    case '\x0f':
                    case '\x16':
                    case '\x1f':
                        break;
                    case '\x03':
                        isColorCode = true;
                        break;
                    default:
                        outputMsg.Append(message[i]);
                        break;
                }
            }
            return outputMsg.ToString();
        }

        public void Message(string nick, string message)
        {
            /* System.Windows.Forms crashes if we don't provide a RTF header. Does not apply to Mono.
             * Commented here because the MSDN doc doesn't tell you. */
            string rtfLine = BARE_HEADER
                + TimeStamp()
                + NickTag(nick)
                + Format(message)
                + BARE_FOOTER;
            Append(rtfLine, true);
        }

        const string ACTION_HEADER = "{\\cf13 * ";
        const string ACTION_FOOTER = "}";

        public void Action(string nick, string action)
        {
            string rtfLine = BARE_HEADER
                + TimeStamp()
                + ACTION_HEADER
                + nick// + " "
                + Format(action)
                + ACTION_FOOTER
                + BARE_FOOTER;

            Append(rtfLine, true);
        }

        const string EVENT_HEADER_GREEN = "{\\cf4\\i *** ";
        const string EVENT_HEADER_RED = "{\\cf5\\i *** ";
        const string EVENT_FOOTER = "}";

        public void Event(string message)
        {
            string rtfLine = BARE_HEADER
                + TimeStamp()
                + EVENT_HEADER_GREEN
                + Format(message)
                + EVENT_FOOTER
                + BARE_FOOTER;

            Append(rtfLine, true);
        }

        void Append(string rtf, bool scroll)
        {
            Select(TextLength, 0);
            SelectedRtf = rtf;
            if (scroll) ScrollToCaret();
        }
    }
}